<template>
  <div class="tr-scroll-column-box" :style="{ width: width, ...boxStyle }">
    <div class="title ft-14 cr-bk-9 mg-bt-16 fw-600">{{ title }}</div>
    <el-input
      :placeholder="placeholder"
      v-model="searchVal"
      clearable
      @keydown.native.enter="searchHandle"
    >
      <i
        slot="prefix"
        class="el-input__icon el-icon-search"
        @click="searchHandle"
      ></i>
    </el-input>

    <div
      class="scrollbar mg-tp-16"
      v-infinite-scroll="loadHandle"
      infinite-scroll-disabled="false"
      infinite-scroll-immediate="true"
      infinite-scroll-distance="1"
    >
      <div
        class="item-box ft-14 fw-400 mg-bt-8"
        :class="{ checked: item.checked }"
        v-for="(item, index) in dataList"
        :key="index"
        @click="itemClickHandle(item)"
      >
        <div class="item-label" v-if="!labelSlotName">
          {{ item[labelProp] }}
        </div>
        <slot v-else v-bind="item" :name="labelSlotName"></slot>
      </div>
      <div class="load-tips ht-28 lh-28 ft-14" v-if="isScroll">
        {{ isLoadAll ? "到底了~" : "加载中..." }}
      </div>
    </div>
  </div>
</template>

<script>
import { getDataList } from "@/api/base/base";
import { get, cloneDeep } from "lodash-es";

export default {
  props: {
    value: {
      default: "",
    },
    url: {
      type: String,
    },
    axiosType: {
      type: String,
      default: "post",
    },
    isAxios: {
      type: Boolean,
      default: true,
    },
    defaultDataList: {
      type: Array,
      default: () => [],
    },
    isScroll: {
      type: Boolean,
      default: true,
    },
    title: {
      type: String,
      default: "-",
    },
    placeholder: {
      type: String,
      default: "请搜索",
    },
    labelProp: {
      type: String,
      default: "label",
    },
    valueProp: {
      type: String,
      default: "value",
    },
    searchProp: {
      type: String,
    },
    dataListProp: {
      type: String,
      default: "data.records",
    },
    size: {
      type: Number,
      default: 30,
    },
    defaultParams: {
      type: Object,
      default: () => {},
    },
    urlConfig: {
      type: Object,
      default: () => {},
    },
    width: {
      type: String,
      default: "206px",
    },
    boxStyle: {
      type: Object,
      default: () => {},
    },
    multiple: {
      type: Boolean,
      default: false,
    },
    labelSlotName: {
      type: String,
    },
    listItemKeys: {
      type: Array,
      default: () => [],
    },
  },
  data() {
    return {
      current: 1,
      searchVal: "",
      isLoadAll: true,
      isRequestFlag: false,
      currentItem: {},
      dataList: [],
      dataListCopy: [],
      createdValue: null,
    };
  },
  watch: {
    searchVal: {
      handler(newVal) {
        if (!newVal && newVal !== 0) this.searchHandle();
      },
    },
    value: {
      handler(newVal) {
        if (this.multiple && !Array.isArray(newVal)) {
          throw new Error("multiple模式下，v-model必须为数组");
        }
        this.setCurrentItem(newVal);
      },
    },
    defaultDataList: {
      immediate: true,
      handler(newVal) {
        this.dataListCopy = this.setListKeys(cloneDeep(newVal));
        if (this.valueProp == "item") {
          this.dataListCopy.forEach((i) => {
            i.item = JSON.stringify(i);
          });
        }
      },
    },
  },
  methods: {
    setListKeys(list) {
      if (this.listItemKeys.length == 0) return list;
      return list.map((item) => {
        const keys = [...this.listItemKeys];
        if (this.valueProp == "item") keys.push("item");
        const keyVal = keys.map((key) => {
          return [key, item[key]];
        });
        return Object.fromEntries(keyVal);
      });
    },
    // 重置选中
    resetChecked() {
      this.$emit("input", this.createdValue);
    },
    setChecked() {
      const keys = Object.keys(this.currentItem);
      this.dataList.forEach((i) => {
        this.$set(i, "checked", false);
      });
      if (keys.length == 0) return;

      if (this.multiple) {
        this.currentItem.forEach((item) => {
          const findObj = this.$findByProperty(
            this.dataList,
            this.valueProp,
            item[this.valueProp]
          );

          if (!findObj) return;
          this.$set(findObj, "checked", true);
        });
      } else {
        const findObj = this.$findByProperty(
          this.dataList,
          this.valueProp,
          this.currentItem[this.valueProp]
        );
        if (!findObj) return;
        this.$set(findObj, "checked", true);
      }
    },
    searchHandle() {
      if (!this.isScroll || !this.isAxios) {
        if (!this.searchVal && this.searchVal !== 0) {
          if (!this.isScroll && this.isAxios) {
            this.initHandle();
          } else {
            this.dataList = this.dataListCopy;
          }
        } else {
          this.dataList = this.dataListCopy.filter((item) =>
            String(item[this.labelProp]).includes(this.searchVal)
          );
        }
        return this.setCurrentItem(this.value);
      }
      this.initHandle();
    },
    async initHandle() {
      this.dataList = [];
      this.current = 1;
      this.isLoadAll = false;
      await this.getDataList();
      this.setCurrentItem(this.value);
    },
    async loadHandle() {
      if (
        this.isRequestFlag ||
        this.isLoadAll ||
        !this.isScroll ||
        !this.isAxios
      )
        return;
      this.current++;
      await this.getDataList();
      this.setCurrentItem(this.value);
    },
    itemClickHandle(item) {
      let inputVal;
      if (this.multiple) {
        let valueList = [...this.value];
        if (item.checked) {
          valueList = valueList.filter((i) => i !== item[this.valueProp]);
        } else {
          valueList.push(item[this.valueProp]);
        }

        inputVal = valueList;
      } else {
        inputVal = item[this.valueProp];
      }
      this.$emit("input", inputVal);

      this.setChecked();
      this.$emit("itemClick", item);
    },
    async getDataList() {
      this.isRequestFlag = true;
      const axiosObj = {
        size: this.size,
        current: this.current,
        ...this.defaultParams,
      };
      axiosObj[this.searchProp] = this.searchVal;
      const [err, resMsg] = await this.$to(
        getDataList(this.url, this.axiosType, axiosObj, this.urlConfig)
      );
      this.isRequestFlag = false;
      if (err) return console.log(err);

      const { data: res } = resMsg;
      let list = get(res, this.dataListProp);
      list = this.setListKeys(list);
      if (this.valueProp === "item") {
        list.forEach((i) => {
          i.item = JSON.stringify(i);
        });
      }
      this.isLoadAll = list.length < this.size;

      this.dataList = [...this.dataList, ...list];
      if (!this.isScroll) this.dataListCopy = cloneDeep(this.dataList);
      this.setChecked();
    },
    setCurrentItem(newVal) {
      if (this.multiple) {
        this.currentItem = [];
        newVal.forEach((val) => {
          const findObj = this.$findByProperty(
            this.dataList,
            this.valueProp,
            val
          );
          if (findObj) this.currentItem.push(findObj);
        });
      } else {
        const findObj = this.$findByProperty(
          this.dataList,
          this.valueProp,
          newVal
        );
        if (findObj) this.currentItem = findObj;
      }
      this.setChecked();
    },
  },
  async created() {
    this.createdValue = cloneDeep(this.value);

    if (this.isAxios) {
      await this.getDataList();
    } else {
      this.dataList = this.setListKeys(cloneDeep(this.defaultDataList));
      if (this.valueProp == "item") {
        this.dataList.forEach((i) => {
          i.item = JSON.stringify(i);
        });
      }
    }

    if (this.multiple && !Array.isArray(this.value))
      throw new Error("multiple模式下，v-model必须为数组");

    this.currentItem = this.multiple ? [] : {};
    this.setCurrentItem(this.value);
  },
};
</script>

<style lang="scss" scoped>
.tr-scroll-column-box {
  height: 100%;
  width: 100%;
  .scrollbar {
    height: calc(100% - 83px);
    overflow-y: auto;
    .item-box {
      border-radius: 3px;
      line-height: 22px;
      cursor: pointer;
      &:hover {
        background-color: $select-hover-background;
      }
      .item-label {
        padding: 2px 8px;
      }
    }
    .load-tips {
      text-align: center;
      color: #c0c4cc;
    }
    .checked {
      color: $main-color;
      background-color: #e9e8fa;
    }
  }
}
</style>
